#!/usr/bin/env python
# -*- coding:utf-8 -*-

"""
# 把一个字符串变成unicode码位的列表
symbols = '$¢£¥€¤'
codes = []
for symbol in symbols:
    codes.append(ord(symbol))

print(codes)
print('=='*20)

# 列表推导式: 把字符串变成unicode码位的另一种写法
symbols = '$¢£¥€¤'
codes = [ord(symbol) for symbol in symbols]
print(codes)

print('=='*20)

x = 'ABC'
dummy = [ord(x) for x in x]
print(x)
print('=='*10)
print(dummy)
"""


# 用列表推导和map/filter组合来创建表单
"""
symbols = '$¢£¥€¤'
beyond_ascii = [ord(s) for s in symbols if ord(s) > 127]
print(beyond_ascii)
beyon_ascii = list(filter(lambda c: c > 127,map(ord,symbols)))
print(beyon_ascii)
"""

# 用列表推导计算笛卡儿积
"""
colors = ['black','white']
sizes = ['S','M','L']
# 先以颜色排列,再以尺码排列.
tshirts = [(color,size) for color in colors for size in sizes]
print(tshirts)
print('===='*15)

# 这里两个循环的嵌套关系和上面for从句先后顺序一样.
for color in colors:
    for size in sizes:
        print((color,size))

print('==='*10)

# 先以尺码排列,再以颜色排列.
tshirt = [(color,size) for size in sizes
                        for color in colors]
print(tshirt)
"""

# 用生成器表达式初始化元组和数组
"""
symbols = '$¢£¥€¤'
print(tuple(ord(symbol) for symbol in symbols))
# array的构造方法需要两个参数,括号是必需的. array构造方法的第一个参数指定了数组中数字的存储方式.
import array
print(array.array('I',(ord(symbol) for symbol in symbols)))
"""

# 使用生成器表达式计算笛卡儿积
"""
# 用生成器表达式后,内存里不会留下一个有6个组合的列表.因为生成器表达式会在每次for循环运行时才生成一个组合.
colors = ['black','white']
sizes = ['S','M','L']
# 生成器表达式逐个产出元素,
for tshirt in ('%s %s'%(c,s) for c in colors for s in sizes):
    print(tshirt)
"""



# 把元组用作记录
"""
# 洛杉矶国际机场的经纬度.
lax_coordinates = (33.9425, -118.408056)
# 东京市的一些信息: 市名,年份,人口,人口变化和面积
city,year,pop,chg,area = ('Tokyo',2003,32450,0.66,8014)
# 一个元组列表,元组的形式.
traveler_ids = [('USA','31195875'),('BRA','CE342567'),('ESP','XDA205856')]
# 在迭代过程中,passport变量被绑定到每个元组上.
for passport in sorted(traveler_ids):
        print('%s/%s' % passport)

print('=='*20)

for country,_ in traveler_ids:  # for循环可以分别提取元组里的元素,叫做拆包.第二个元素没用,赋值给_占位符.
        print(country)
"""


# 元组拆包
"""
lax_coordinates = (33.9425,-118.408056)
latitude,longitude = lax_coordinates # 元组拆包
print(latitude)
print('--'*20)
print(longitude)
"""

# 用*运算符把一个可迭代对象拆开作为函数的参数.
"""
print(divmod(20,8))
t = (20,8)
print(divmod(*t))
quotient,remainder = divmod(*t)
print(quotient,remainder)
"""

# 元组拆包的用法是让一个函数可以用元组的形式返回多个值,然后调用函数的代码就接受这些返回值.
"""
import os
_,filename = os.path.split('F:\Document-PDF\docker\docker安装与使用.pdf')
print(filename)
"""

# 用*来处理剩下的元素,这个概念被用到平行赋值中.
"""
a,b,*rest = range(5)
print(a,b,rest,sep= ',')
a,b,*rest = range(3)
print(a,b,rest,sep= ',')
print('--'*20)
"""
# 在平行赋值中,*前缀只能用在一个变量名前面,但是这个变量可以出现在赋值表达式的任意位置.
"""
a,*body,c,d = range(5)
print(a,body,c,d,end='\n')
print('--'*20)
*head,b,c,d = range(6)
print(head,b,c,d,end='\n')
"""

# 用嵌套元组来获取经度
# 每个元组内有4个元素,最后一个元素是一对坐标.
"""
metro_areas = [
        ('Tokyo','JP',36.933,(35.68,139.691)),
        ('Delhi NCR','IN',21.935,(28.613,77.208)),
        ('Mexico City','MX',20.142,(19.433,-99.133)),
        ('New York-Newark','US',20.104,(40.808,-74.020)),
        ('Sao Paulo','BR',19.649,(-23.547,-46.635)),
]

print('{:15} | {:^9} | {:^9}'.format('','lat.','long.'))
fmt = '{:15} | {:9.4f} | {:9.4f}'
# 把输入元组的最后一个元素拆包到由变量构成的元组里,就获取了坐标.
for name,cc,pop,(latitude,longitude) in metro_areas:
        if longitude <= 0: # 这个条件判断把输出限制在西半球的城市.
                print(fmt.format(name,latitude,longitude))
"""


# 定义和使用具名元组
"""
from collections import namedtuple
# 创建一个具名元组需要两个参数,一个是类名,另一个是类的各个字段的名字.
City = namedtuple('City','name country population coordinates')
# 存放在对应字段里的数据要以一串参数的形式传入到构造函数中(注意:元组的构造函数却只接受单一的可迭代对象)
tokyo = City('Tokyo','JP',36.933,(35.689,139.691))
print(tokyo)
print(tokyo.population)  # 可以通过字段名或者位置来获取一个字段的信息.
print(tokyo.coordinates)
print(tokyo[1])
"""

# 具名元组的属性和方法(接续前一个示例)
"""
print(City._fields) # _fields属性是一个包含这个类所有字段名称的元组.
LatLong = namedtuple('LatLong','lat long')
delhi_data = ('Delhi NCR','IN',21.935,LatLong(28.613,77.208))
delhi = City._make(delhi_data) # _make()通过接受一个可迭代对象来生成这个类的一个实例.
print(delhi._asdict())  # _asdict()把具名元组以collections.OrderedDict形式返回.把元组里的信息友好呈现.
for key,value in delhi._asdict().items():
        print(key + ':',value)
"""

"""
l = [10,20,30,40,50,60]
print(l[:2]) # 在下标2的地方分割
print(l[2:]) 
print(l[:3]) # 在下标3的地方分割.
print(l[3:])
"""
# 对对象进行切片
"""
s = 'bicycle' 
print(s[::3])
print(s[::-1])
print(s[::-2])
"""

# 给切片赋值
"""
li = list(range(10))
print(li)
li[2:5] = [20,30]
print(li)
print('--'*20)

del li[5:7]
print(li)
print('--'*20)

li[3::2] = [11,22]
print(li)
print('--'*20)

li[2:5] = 100  # 如果赋值的对象时一个切片,那么赋值语句的右侧必须是个可迭代对象。即使只有单独一个值,也要把它转换成可迭代的序列.

li[2:5] = [100]
print(li)
"""

# 建立由列表组成的列表.
# 一个包含3个列表的列表,嵌套的3个列表各自有3个元素来代表井字游戏的一行方块.
"""
board = [['_'] * 3 for i in range(3)] # 建立一个包含3个列表的列表,被包含的3个列表各自有3个元素.打印出这个嵌套列表.
print(board)
board[1][2] = 'X' # 把第1行第2列的元素标记为X,再打印出这个列表.
print(board)
"""

"""
board = []
for i in range(3):
        row = ['_'] * 3 # 每次迭代中都新建了一个列表,作为新的一行追加到游戏板.
        board.append(row)

print(board)
print(board[2][0] = 'X')
print(board)  # 只有第2行的元素被修改.

"""

# *= 在可变和不可变序列上的作用
"""
lb = [1,2,3]
print(id(lb))
lb *= 2
print(lb)
print(id(lb))
print('--'*20)
t = (1,2,3)
print(id(t))
t *= 2
print(id(t))

# 输出结果:
2410605849736  # 开始时列表的的ID。
[1, 2, 3, 1, 2, 3]
2410605849736  # 运用增量乘法后,列表的ID没变,新元素追加到列表上.
2410603270864  # 元组最开始的ID。
2410603023336  # 运用增量乘法后,新的元组被创建.
"""

# sort和sorted方法.
"""
fruits = ['grape','raspberry','apple','banana']
print(sorted(fruits))
print(fruits)
print(sorted(fruits,reverse=True))
print(sorted(fruits,key=len))
print(sorted(fruits,key=len,reverse=True))
print(fruits)
print(fruits.sort())
print(fruits)
"""

# 用bisect来搜索
# 在有序序列中用bisect查找某个元素的插入位置
"""
import bisect
import sys

HAYSTACK = [1,4,5,6,8,12,15,20,21,23,23,26,29,30]
NEEDLES = [0,1,2,5,8,10,22,23,29,30,31]

ROW_FMT = '{0:2d} @ {1:2d}  {2}{0:<2d}'

def demo(bisect_fn):
    for needle in reversed(NEEDLES):
        position = bisect_fn(HAYSTACK,needle)  # 用特定bisect函数来计算元素出现的位置.
        offset = position * '  |'  # 利用该位置算出需要几个分隔符号.
        print(ROW_FMT.format(needle,position,offset))  # 把元素和其应该出现的位置打印出来.      

if __name__=='__main__':

    if sys.argv[-1] == 'left':  # 根据命令上最后一个参数来选用bisect函数.
        bisect_fn = bisect.bisect_left
    else:
        bisect_fn = bisect.bisect
    
    print('DEMO:',bisect_fn.__name__) # 把选定的函数打印出来.
    print('haystack ->',' '.join('{}'.format(n)for n in HAYSTACK))
    demo(bisect_fn)
"""


# 根据一个分数,找到它所对应的成绩
"""
import bisect
def grade(score,breakpoints=[60,70,80,90],grades='FDCBA'):
    i = bisect.bisect(breakpoints,score)
    return grades[i]

print([grade(score) for score in [33,99,77,70,89,90,100]])
"""

# 用bisect.insort插入新元素
# insort可以保持有序序列的顺序
"""
import bisect
import random

SIZE = 7
random.seed(1729)

my_list = []
for i in range(SIZE):
        new_item = random.randrange(SIZE*2)
        bisect.insort(my_list,new_item)
        print('{} ->'.format(new_item),my_list)
"""


# 从创建一个有1000万个随机浮点数的数组开始,到如何把这个数组存放到文件里,再到如何从文件读取这个数组.
# 一个浮点型数组的创建,存入文件和从文件读取的过程
"""
from array import array  # 引入array类型
from random import random

# 利用一个可迭代对象来建立一个双精度浮点数组(类型码是'd'),现在用的可迭代对象是生成器表达式.
floats = array('d',(random() for i in range(10**7)))  
print(floats[-1])  # 查看数组的最后一个元素.

fp = open('floats.bin','wb')
floats.tofile(fp)  # 把数组存入一个二进制文件里.
fp.close()
print('--'*20)
floats2 = array('d') # 新建一个双精度浮点空数组.
fp = open('floats.bin','rb')
floats2.fromfile(fp,10**7) # 把1000万个浮点数从二进制文件里读取出来.
fp.close()
print(floats2[-1])   # 查看新数组的最后一个元素.
print(floats2 == floats)  # 检查两个数组的内容是否一样.
"""


# 利用memoryview修改了一个数组的某个字节,这个数组的元素是16位二进制整数.
# 改变数组中的一个字节来更新数组里某个元素的值.
"""
import array   # 引入array类型

# 利用含有5个短整型有符号整数的数组(类型码是'h',)创建一个memoryview.
numbers = array.array('h',[-2,-1,0,1,2])
memv = memoryview(numbers)
print(len(memv))
print(memv[0])

memv_oct = memv.cast('B')  # 创建一个memv_oct,把memv里的内容转换成'B'类型。也就是无符号字符.
memv_oct.tolist() # 以列表形式查看memv_oct内容。
memv_oct[5] = 4 # 把位于位置5的字节赋值成4.
print(numbers)  # 因为把占2个字节的整数的高位字节改成了4。
"""


# 对numpy.ndarray的行和列进行基本操作。
# 安装numpy: pip install numpy
"""
import numpy
a = numpy.arange(12) # 新建一个0~11的整数的numpy.ndarry

print(a)
print(type(a))
print(a.shape) # 数组的维度: 是一个一维的,有12个元素的数组.
a.shape = 3, 4  # 把数组变成二维的
print('--'*20)
print(a)
print('--'*20)
print(a[2])  # 打印第二行
print('--'*20)
print(a[2,1]) # 打印第2行第1列的元素.
print('--'*20)
print(a[:,1]) # 把第1列打印出来.
print('--'*20)
print(a.transpose())  # 把行和列交换,得到一个新数组.
"""


# numpy可以对numpy.ndarray中的元素进行抽象的读取,保存和其他操作
"""
import numpy

floats = numpy.loadtxt('floats-10M-lines.txt')
print(floats[-3:])
floats *= .5
print(floats[-3:])

from time import perf_counter as pc 

t0 = pc()
floats /= 3 
print(pc() - t0)
print('--'*10)
print(numpy.save('floats-10M',floats))
floats2 = numpy.load('floats-10M.npy','r+')
floats2 *= 6
print(floats2[-3:])
"""


# 使用双向队列
from collections import deque
dq = deque(range(10),maxlen=10) # maxlen可选参数,代表这个队列可以容纳的元素的数量.
print(dq)
dq.rotate(3)  # 队列的旋转操作接受一个参数n,当n>0时,队列的最右边的n个元素会被移动到队列的左边.
# 当n< 0时,最左边的n个元素会被移动到右边.
print(dq)
dq.rotate(-4)
print(dq)
dq.appendleft(-1) #对已满(len(d) == d.maxlen)的队列做尾部添加操作时,它头部的元素会被删除掉.
print(dq)
dq.extend([11,22,33]) # 在尾部添加3个元素会挤掉-1,1和2. 
print(dq)
dq.extendleft([10,20,30,40]) # extendleft(iter)方法会把迭代器里的元素逐个添加到双向队列的左边,因此迭代器里的元素会逆序出现在队列里.
print(dq)
